package com.ruoyi.plus.service.impl;

import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.shiro.service.SysPasswordService;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.plus.constant.TenantConstants;
import com.ruoyi.plus.domain.SysTenant;
import com.ruoyi.plus.mapper.SysTenantMapper;
import com.ruoyi.plus.service.ISysTenantService;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;

/**
 * 租户管理Service业务层处理
 * <p>
 * 租户表逻辑
 * 添加租户时验证
 * 1.租户表中不存在相同的登录账号、手机号、邮箱。
 * 2.用户表中不存在相同的登录账号、手机号、邮箱。
 * <p>
 * 添加租户时同时初始化数据
 * 1.创建该租户的根部门。
 * 2.创建该租户的管理员角色。
 * 3.创建该租户的管理员用户。
 * 4.为该用户绑定部门和管理员角色。
 * 5.绑定角色和部门。
 * <p>
 * 为租户进行菜单授权：
 * 1.界面添加按钮选择为该租户开通哪些菜单。
 * 2.开通的菜单和该租户管理员角色绑定在一起。
 * <p>
 * 编辑租户：
 * 登录账号不可编辑，其他信息都可编辑，编辑时再次验证手机号和邮箱。
 * <p>
 * 重置密码：
 * 同时重置租户中保存的密码和用户表中保存的密码，因为此密码用于登录。
 * 用户表中的用户修改密码不影响租户表中的密码。
 * <p>
 * 删除租户：
 * 提醒用户慎重删除，逻辑删除租户和逻辑删除该租户下的所有用户数据。
 *
 * @author likun
 * @date 2020-01-13
 */
@Service
public class SysTenantServiceImpl implements ISysTenantService {
    @Autowired
    private SysTenantMapper sysTenantMapper;
    @Autowired
    private SysDeptMapper deptMapper;
    @Autowired
    private SysMenuMapper menuMapper;
    @Autowired
    private SysRoleMapper roleMapper;
    @Autowired
    private SysRoleDeptMapper roleDeptMapper;
    @Autowired
    private SysRoleMenuMapper roleMenuMapper;
    @Autowired
    private SysUserMapper userMapper;
    @Autowired
    private SysUserRoleMapper userRoleMapper;
    @Autowired
    private ISysUserService userService;
    @Autowired
    private SysPasswordService passwordService;
    @Autowired
    private ISysRoleService roleService;

    /**
     * 查询租户管理
     *
     * @param tenantId 租户管理ID
     * @return 租户管理
     */
    @Override
    public SysTenant selectSysTenantById(Long tenantId) {
        return sysTenantMapper.selectSysTenantById(tenantId);
    }

    /**
     * 查询租户管理列表
     *
     * @param sysTenant 租户管理
     * @return 租户管理
     */
    @Override
    public List<SysTenant> selectSysTenantList(SysTenant sysTenant) {
        return sysTenantMapper.selectSysTenantList(sysTenant);
    }

    /**
     * 新增租户
     * 添加租户时同时初始化数据
     * 1.创建该租户的根部门。
     * 2.创建该租户的管理员角色。
     * 3.创建该租户的管理员用户。
     * 4.为该用户绑定部门和管理员角色。
     * 5.绑定角色和部门。
     *
     * @param sysTenant 租户管理
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public int insertSysTenant(SysTenant sysTenant) {
        //校验用户名、手机号、邮箱
        if (TenantConstants.TENANT_NAME_NOT_UNIQUE.equals(checkLoginNameUnique(sysTenant.getLoginName()))) {
            return 0;
        }
        if (TenantConstants.TENANT_PHONE_NOT_UNIQUE.equals(checkMobileUnique(sysTenant))) {
            return 0;
        }
        if (TenantConstants.TENANT_EMAIL_NOT_UNIQUE.equals(checkEmailUnique(sysTenant))) {
            return 0;
        }
        sysTenant.setSalt(ShiroUtils.randomSalt());
        sysTenant.setPassword(passwordService.encryptPassword(sysTenant.getLoginName(), sysTenant.getPassword(), sysTenant.getSalt()));
        sysTenant.setCreateBy(ShiroUtils.getLoginName());
        sysTenant.setCreateTime(DateUtils.getNowDate());
        sysTenantMapper.insertSysTenant(sysTenant);

        SysDept sysDept = initDept(sysTenant);
        sysTenant.setDeptId(sysDept.getDeptId());
        SysRole sysRole = initRole(sysTenant);
        sysTenant.setRoleId(sysRole.getRoleId());
        SysUser sysUser = initUser(sysTenant);
        sysTenant.setUserId(sysUser.getUserId());

        //更新初始化的id到租户表.
        sysTenantMapper.updateSysTenant(sysTenant);

        //插入角色部门对应关系并修改租户id
        SysRoleDept sysRoleDept = new SysRoleDept();
        sysRoleDept.setRoleId(sysRole.getRoleId());
        sysRoleDept.setDeptId(sysDept.getDeptId());
        roleDeptMapper.batchRoleDept(Arrays.asList(sysRoleDept));

        //插入用户角色对应关系并修改租户id
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setUserId(sysUser.getUserId());
        sysUserRole.setRoleId(sysRole.getRoleId());
        userRoleMapper.batchUserRole(Arrays.asList(sysUserRole));

        return 1;
    }

    private SysDept initDept(SysTenant sysTenant) {
        //初始化部门数据
        SysDept sysDept = new SysDept();
        sysDept.setDeptName(sysTenant.getCompany());
        sysDept.setOrderNum("1");
        sysDept.setParentId(0L);
        sysDept.setAncestors("0");
        sysDept.setLeader(sysTenant.getName());
        sysDept.setPhone(sysTenant.getMobile());
        sysDept.setEmail(sysTenant.getEmail());
        sysDept.setStatus("0");
        sysDept.setDelFlag("0");
        sysDept.setCreateBy(ShiroUtils.getLoginName());
        sysDept.setCreateTime(DateUtils.getNowDate());
        sysDept.setRemark("租户创建-初始化部门");
        deptMapper.insertDept(sysDept);

        sysDept.setTenantId(sysTenant.getId());
        sysTenantMapper.updateDeptTenant(sysDept);
        return sysDept;
    }

    private SysRole initRole(SysTenant sysTenant) {
        //初始化角色
        SysRole sysRole = new SysRole();
        sysRole.setRoleKey("admin");
        sysRole.setRoleName("管理员");
        sysRole.setRoleSort("1");
        sysRole.setDataScope("1");
        sysRole.setStatus("0");
        sysRole.setDelFlag("0");
        sysRole.setCreateBy(ShiroUtils.getLoginName());
        sysRole.setCreateTime(DateUtils.getNowDate());
        sysRole.setRemark("租户创建-初始化角色");
        roleMapper.insertRole(sysRole);

        sysRole.setTenantId(sysTenant.getId());
        sysTenantMapper.updateRoleTenant(sysRole);
        return sysRole;
    }

    private SysUser initUser(SysTenant sysTenant) {
        //初始化管理员用户
        SysUser sysUser = new SysUser();
        sysUser.setDeptId(sysTenant.getDeptId());
        sysUser.setLoginName(sysTenant.getLoginName());
        sysUser.setPassword(sysTenant.getPassword());
        sysUser.setSalt(sysTenant.getSalt());
        sysUser.setPhonenumber(sysTenant.getMobile());
        sysUser.setEmail(sysTenant.getEmail());
        sysUser.setUserName(sysTenant.getName());
        sysUser.setSex("2");
        sysUser.setStatus("0");
        sysUser.setDelFlag("0");
        sysUser.setCreateBy(ShiroUtils.getLoginName());
        sysUser.setCreateTime(DateUtils.getNowDate());
        sysUser.setRemark("租户创建-初始化管理员用户");
        userMapper.insertUser(sysUser);

        sysUser.setTenantId(sysTenant.getId());
        sysTenantMapper.updateUserTenant(sysUser);
        return sysUser;
    }


    /**
     * 修改租户管理
     *
     * @param sysTenant 租户管理
     * @return 结果
     */
    @Override
    public int updateSysTenant(SysTenant sysTenant) {
        sysTenant.setUpdateTime(DateUtils.getNowDate());
        return sysTenantMapper.updateSysTenant(sysTenant);
    }

    /**
     * 删除租户管理对象
     * 提醒用户慎重删除，逻辑删除租户和逻辑删除该租户下的所有用户数据。
     *
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteSysTenantByIds(String ids) {
        String[] tenantIds = Convert.toStrArray(ids);
        for (String tenantId : tenantIds) {
            deleteSysTenantById(Long.valueOf(tenantId));
        }
        return 1;
    }

    /**
     * 删除租户管理对象
     * 提醒用户慎重删除，逻辑删除租户和逻辑删除该租户下的所有用户数据。
     *
     * @param tenantId 租户管理ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public int deleteSysTenantById(Long tenantId) {
        //删除该租户下所有用户
        sysTenantMapper.deleteUsersByTenantId(tenantId);
        //删除该租户下所有角色
        sysTenantMapper.deleteRolesByTenantId(tenantId);
        //删除该租户下所有部门
        sysTenantMapper.deleteDeptsByTenantId(tenantId);
        //删除租户
        return sysTenantMapper.deleteSysTenantById(tenantId);
    }

    /**
     * 修改密码
     * 同时重置租户中保存的密码和用户表中保存的密码，因为此密码用于登录。
     * 用户表中的用户修改密码不影响租户表中的密码。
     *
     * @param tenant 租户信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public int resetUserPwd(SysTenant tenant) {
        String salt = ShiroUtils.randomSalt();
        String password = passwordService.encryptPassword(tenant.getLoginName(), tenant.getPassword(), salt);
        tenant.setSalt(salt);
        tenant.setPassword(password);

        //修改用户登录密码
        SysUser sysUser = userMapper.selectUserByLoginName(tenant.getLoginName());
        if (sysUser != null) {
            sysUser.setSalt(salt);
            sysUser.setPassword(password);
            userMapper.updateUser(sysUser);
        }

        return updateSysTenant(tenant);
    }

    /**
     * 校验登录名称是否唯一
     *
     * @param loginName 用户名
     * @return
     */
    @Override
    public String checkLoginNameUnique(String loginName) {
        //校验租户表
        int count = sysTenantMapper.checkLoginNameUnique(loginName);
        if (count > 0) {
            return TenantConstants.TENANT_NAME_NOT_UNIQUE;
        }
        //校验用户表
        if (UserConstants.USER_NAME_NOT_UNIQUE.equals(userService.checkLoginNameUnique(loginName))) {
            return TenantConstants.TENANT_NAME_NOT_UNIQUE;
        }
        return TenantConstants.TENANT_NAME_UNIQUE;
    }

    /**
     * 校验用户名称是否唯一
     *
     * @param tenant 用户信息
     * @return
     */
    @Override
    public String checkMobileUnique(SysTenant tenant) {
        //校验租户表
        Long id = StringUtils.isNull(tenant.getId()) ? -1L : tenant.getId();
        SysTenant info = sysTenantMapper.checkMobileUnique(tenant.getMobile());
        if (StringUtils.isNotNull(info) && info.getId().longValue() != id.longValue()) {
            return TenantConstants.TENANT_PHONE_NOT_UNIQUE;
        }

        //校验用户表
        SysUser sysUser = new SysUser();
        sysUser.setPhonenumber(tenant.getMobile());
        if (UserConstants.USER_PHONE_NOT_UNIQUE.equals(userService.checkPhoneUnique(sysUser))) {
            return TenantConstants.TENANT_PHONE_NOT_UNIQUE;
        }
        return TenantConstants.TENANT_PHONE_UNIQUE;
    }

    /**
     * 校验email是否唯一
     *
     * @param tenant 用户信息
     * @return
     */
    @Override
    public String checkEmailUnique(SysTenant tenant) {
        //校验租户表
        Long id = StringUtils.isNull(tenant.getId()) ? -1L : tenant.getId();
        SysTenant info = sysTenantMapper.checkEmailUnique(tenant.getEmail());
        if (StringUtils.isNotNull(info) && info.getId().longValue() != id.longValue()) {
            return TenantConstants.TENANT_EMAIL_NOT_UNIQUE;
        }

        //校验用户表
        SysUser sysUser = new SysUser();
        sysUser.setEmail(tenant.getEmail());
        if (UserConstants.USER_EMAIL_NOT_UNIQUE.equals(userService.checkEmailUnique(sysUser))) {
            return TenantConstants.TENANT_EMAIL_NOT_UNIQUE;
        }
        return TenantConstants.TENANT_EMAIL_UNIQUE;
    }

    /**
     * 为租户进行菜单授权：
     * 1.界面添加按钮选择为该租户开通哪些菜单。
     * 2.开通的菜单和该租户管理员角色绑定在一起。
     *
     * @param sysTenant 租户
     * @param menuIds   菜单
     * @return 结果
     */
    @Override
    public int grantAuthSave(SysTenant sysTenant, Long[] menuIds) {

        //更新初始角色与所选择的菜单的进行授权.
        SysRole sysRole = new SysRole();
        sysRole.setRoleId(sysTenant.getRoleId());
        sysRole.setMenuIds(menuIds);
        roleService.updateRole(sysRole);

        return 1;
    }
}
